package com.kim.common.exception;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.kim.common.resp.CodeMsg;
import com.kim.common.resp.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.NestedRuntimeException;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletResponse;
import java.util.stream.Collectors;


@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {

    @Autowired
    private ObjectMapper objectMapper;

    /**
     * 没有捕获的异常全部在这里处理
     *
     * @param e
     * @return
     */
    @ExceptionHandler(Throwable.class)
    @ResponseBody
    public void throwable(Throwable e, HttpServletResponse response) {
        log.error("error class:{}  mes: {}", e.getClass().getName(), e.getMessage());
        e.printStackTrace();
        //服务器内部错误
        Result<Object> error = Result.error(CodeMsg.ERROR_SYSTEM);
        Result.responseWriter(objectMapper, response, error);
    }

    /**
     * 没有捕获的异常全部在这里处理
     *
     * @param e
     * @return
     */
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public void exception(Exception e, HttpServletResponse response) {
        log.error("error class:{}  mes: {}", e.getClass().getName(), e.getMessage());
        e.printStackTrace();
        //服务器内部错误
        Result<Object> error = Result.error(CodeMsg.ERROR_SYSTEM);
        Result.responseWriter(objectMapper, response, error);
    }

    /**
     * 运行时异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(RuntimeException.class)
    @ResponseBody
    public void runtimeException(RuntimeException e, HttpServletResponse response) {
        log.error("error class:{}  mes: {}", e.getClass().getName(), e.getMessage());
        e.printStackTrace();
        //服务器内部错误
        Result<Object> error = Result.error(CodeMsg.ERROR_SYSTEM.getCode(), e.getMessage());
        Result.responseWriter(objectMapper, response, error);
    }

    @ExceptionHandler(ServletException.class)
    @ResponseBody
    public void servletException(ServletException e, HttpServletResponse response) {
        log.error("error class:{}  mes: {}", e.getClass().getName(), e.getMessage());
        e.printStackTrace();
        //服务器内部错误
        Result<Object> error = Result.error(CodeMsg.ERROR_SYSTEM.getCode(), e.getMessage());
        Result.responseWriter(objectMapper, response, error);
    }


    /**
     * 输入参数校验不通过
     *
     * @param e
     * @return
     */
    @ExceptionHandler({MethodArgumentNotValidException.class})
    @ResponseBody
    public void methodArgumentNotValidException(MethodArgumentNotValidException e, HttpServletResponse response) {
        String errorMes = e.getBindingResult().getAllErrors().stream().map(ObjectError::getDefaultMessage).collect(Collectors.joining(","));
        log.error("error class:{}  mes: {} errorMes: {} ", e.getClass().getName(), e.getMessage(), errorMes);
        e.printStackTrace();
        //输入参数不合法
        Result<Object> error = Result.error(CodeMsg.PARAM_FAIL.getCode(), errorMes);
        Result.responseWriter(objectMapper, response, error);
    }

    /**
     * 数据库 dao层异常
     *
     * @param e
     * @param response
     */
    @ExceptionHandler({NestedRuntimeException.class})
    @ResponseBody
    public void dataAccessException(NestedRuntimeException e, HttpServletResponse response) {
        log.error("error class:{}  mes: {}", e.getClass().getName(), e.getMessage());
        e.printStackTrace();
        //服务器内部错误
        Result<Object> error = Result.error(CodeMsg.ERROR_SYSTEM);
        Result.responseWriter(objectMapper, response, error);
    }

    /**
     * 自定义异常的父类
     *
     * @param e
     * @return
     */
    @ExceptionHandler(BusinessException.class)
    @ResponseBody
    public void BusinessException(BusinessException e, HttpServletResponse response) {
        log.error("error class:{}  mes: {}", e.getClass().getName(), e.getMessage());
        e.printStackTrace();
        Result<Object> error = Result.error(e.getErrCode(), e.getMessage());
        Result.responseWriter(objectMapper, response, error);
    }
}
